package my.dao.impl;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import my.dao.Dao;
import my.dao.DaoException;
import my.dao.NoFoundRowException;
import my.dao.NullUniqueResultRowMapper;
import my.dao.RowMapper;
/**
 * 
 * @author 夏冬琦
 * @version 3.0
 *
 */
public abstract class AbstractDao implements Dao {
		
	protected AbstractDao(DataSource dataSource){
		try {
			if(dataSource == null) {
				throw new DaoException("DataSource对象为null！");
			}
			conn=dataSource.getConnection();
		} catch (SQLException e) {
			throw new DaoException("创建Dao对象失败！",e);
		}
	}
	
	protected AbstractDao(DaoConfig cfg)throws DaoException{
		try {				
			conn=cfg.getConnection();
		} catch (SQLException e) {
			throw new DaoException("创建Dao对象失败！",e);
		}
			
	}
	
	protected AbstractDao(){
		try {				
			conn=DaoConfig.getInstance().getConnection();
		} catch (SQLException e) {
			throw new DaoException("创建Dao对象失败！",e);
		}
	}
	

	protected boolean closed=true;
	
	protected Connection conn;
	
	
	protected Set<PreparedStatement> pstmts=//缓存PreparedStatement对象的集合
			new HashSet<PreparedStatement>();
	
	protected Set<ResultSet> rss=//缓存ResultSet对象的集合
			new HashSet<ResultSet>();
	
	
	public Connection getConn() {
		return conn;
	}
	
	//判断sql是否为存储过程调用
	private boolean isCallableSql(String sql) {
		String trimSql = sql.trim();
		return trimSql.startsWith("{")&&trimSql.endsWith("}");
	}
	
	protected PreparedStatement baseCreatePreparedStatement(String sql) throws SQLException{
		System.out.println("SQL: "+sql);	
		
		PreparedStatement pstmt = null;
		if(isCallableSql(sql)) {//是否为存储过程调用
			pstmt = conn.prepareCall(sql);
		}else {
			pstmt = conn.prepareStatement(sql);
		}
		
		pstmts.add(pstmt);//将预编译语句对象放入缓存PreparedStatement对象的集合
		return pstmt;
	}
	
	//为PreparedStatement对象设置sql占位符参数
	protected PreparedStatement baseSetArgs4PreparedStatement(PreparedStatement pstmt,Object... args) throws SQLException{
		
		StringBuilder builder=new StringBuilder("{");
		if(args!=null){
			for(int i=0;i<args.length;i++){
				if(i==0){
					builder.append("["+args[i]+"]");
				}else{
					builder.append(",["+args[i]+"]");
				}
			}
		}
		
		builder.append("}");
		System.out.println("参数: "+builder.toString());
		
		if(args!=null){
			for(int i=0;i<args.length;i++){
				if(args[i] instanceof java.util.Date){
					java.util.Date date=(java.util.Date)args[i];
					/*pstmt.setDate(i+1, new java.sql.Date(date.getTime()));*/
					pstmt.setTimestamp(i+1, new java.sql.Timestamp(date.getTime()));
				}else{
					pstmt.setObject(i+1, args[i]);
				}
			}
		}
		
		return pstmt;
	}
	
	
	protected ResultSet baseQuery(PreparedStatement pstmt) throws SQLException{
		
		ResultSet rs = null;
		if(pstmt instanceof CallableStatement) {
			
			CallableStatement cst = (CallableStatement) pstmt;
			cst.execute();
			
			do {
				ResultSet temp = cst.getResultSet();	
				if(temp != null) {
					//执行getMoreResults方法后，刚刚通过getResultSet方法获取的ResultSet对象即自动隐式关闭，因此此处不需要缓存。
					//rss.add(temp);
					rs = temp;
					
					break;
				}
			}while(cst.getMoreResults());			
			
			if(rs == null) {
				throw new DaoException("执行存储过程没有获得结果集!");
			}
			
			rss.add(rs);
			
		}else {
			rs = pstmt.executeQuery();
			rss.add(rs);
		}
		
		
		
		return rs;
	}
	
	protected ResultSet baseQuery(String sql, Object... args) throws SQLException{
		return baseQuery(baseSetArgs4PreparedStatement(baseCreatePreparedStatement(sql), args));
	}
	
	protected  void baseClose() throws DaoException {
		
		
		//关闭ResultSet
		for(ResultSet rs:rss){
			try {
				if(rs!=null){
					rs.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		rss.clear();//清空缓存ResultSet对象的集合
		
		//关闭PreparedStatement
		for(PreparedStatement pst:pstmts){
			try {
				if(pst!=null){
					pst.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		pstmts.clear();
		//关闭连接
		try {
			if(conn!=null&&!conn.isClosed()){
				conn.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		conn=null;
		
		this.closed=true;
	}
	
	protected int baseUpdate(String sql,Object... args) throws SQLException{
		
		PreparedStatement pstmt = baseCreatePreparedStatement(sql);
		
		if(pstmt instanceof CallableStatement) {			
			baseSetArgs4PreparedStatement(pstmt, args).execute();
			int count = -1;
			do {
				int temp = pstmt.getUpdateCount();
				if(temp!=-1) count = temp;
			}while(pstmt.getMoreResults());
			
			return count;				
			
		}else {
			return baseSetArgs4PreparedStatement(pstmt, args).executeUpdate();		
		}
			
	}
	
 	protected List<Map<String,Object>> baseMakeResultSetToListOfMap(ResultSet rs) throws SQLException{
		List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
		
		ResultSetMetaData md=rs.getMetaData();
		while(rs.next()){
			Map<String,Object> map=new HashMap<String,Object>();
			for(int i=1;i<=md.getColumnCount();i++){
				//LOG.debug(md.getColumnLabel(i)+","+md.getColumnName(i));
				map.put(md.getColumnLabel(i).toLowerCase(), rs.getObject(i));
			}
			list.add(map);
		}
		
		return list;
	}
 	/**
 	 * 
 	 * @param rs
 	 * @return 返回Map<String,Object>集合，若未查到数据返回null
 	 * @throws SQLException
 	 */
 	protected Map<String,Object> baseMakeResultSetToUniqueMap(ResultSet rs) throws SQLException{		
		
		ResultSetMetaData md=rs.getMetaData();
		if(rs.next()){
			Map<String,Object> map=new HashMap<String,Object>();
			for(int i=1;i<=md.getColumnCount();i++){				
				map.put(md.getColumnLabel(i).toLowerCase(), rs.getObject(i));
			}
			return map;
		}
		
		return null;
	}
 	protected List<Map<String, Object>> baseQueryListOfMap(String sql, Object... args) throws SQLException{ 		
 		ResultSet rs=baseQuery(baseSetArgs4PreparedStatement(baseCreatePreparedStatement(sql), args));		
 		return baseMakeResultSetToListOfMap(rs);
 	}
 	
 	/**
 	 * 
 	 * @param sql
 	 * @param args
 	 * @return 返回Map集合，若未查到数据返回null
 	 * @throws SQLException
 	 */
 	protected Map<String, Object> baseQueryUniqueMap(String sql, Object... args) throws SQLException{ 		
 		ResultSet rs=baseQuery(baseSetArgs4PreparedStatement(baseCreatePreparedStatement(sql), args));		
 		return baseMakeResultSetToUniqueMap(rs);
 	}
 	
 	protected List<Object[]> baseMakeResultSetToListOfArray(ResultSet rs) throws SQLException{
		List<Object[]> list=new ArrayList<Object[]>();
		
		ResultSetMetaData md=rs.getMetaData();
		while(rs.next()){
			Object[] array=new Object[md.getColumnCount()];
			for(int i=0;i<array.length;i++){					
				array[i]=rs.getObject(i+1);
			}
			list.add(array);
		}
		
		return list;
	}
 	
 	
 	
 	protected List<Object[]> baseQueryListOfArray(String sql, Object... args) throws SQLException{ 		
 		ResultSet rs=baseQuery(baseSetArgs4PreparedStatement(baseCreatePreparedStatement(sql), args));		
 		return baseMakeResultSetToListOfArray(rs);	 		
 	}
 	
 	protected Object[] baseMakeResultSetToUniqueArray(ResultSet rs) throws SQLException{
		
		ResultSetMetaData md=rs.getMetaData();
		if(rs.next()){
			Object[] array=new Object[md.getColumnCount()];
			for(int i=0;i<array.length;i++){					
				array[i]=rs.getObject(i+1);
			}
			return array;
		}
		
		return null;
	}
 	
 	protected Object[] baseQueryUniqueArray(String sql, Object... args) throws SQLException{ 		
 		ResultSet rs=baseQuery(baseSetArgs4PreparedStatement(baseCreatePreparedStatement(sql), args));		
 		return baseMakeResultSetToUniqueArray(rs);	 		
 	}
	
	protected <T> List<T> baseMakeResultSetToList(RowMapper<T> mapper,ResultSet rs) throws DaoException, SQLException{
		List<T> list=new ArrayList<T>();
		while(rs.next()){
			list.add(mapper.currRow2Obj(rs));
		}
		return list;
	}
	
	
	
	protected <T> List<T> baseQuery(RowMapper<T> mapper, String sql, Object... args) throws DaoException, SQLException{
		
		ResultSet rs=baseQuery(baseSetArgs4PreparedStatement(baseCreatePreparedStatement(sql), args));			
		return baseMakeResultSetToList(mapper, rs);		
		
	}
	/**
	 * 
	 * @param mapper
	 * @param rs
	 * @return 返回封装一条数据记录的对象。当没有查询到结果，若mapper是AutoBeanRowMapperImpl的实例对象，则返回null，否则抛出异常NoFoundRowException。
	 * @throws NoFoundRowException
	 * @throws DaoException
	 * @throws SQLException
	 */
	protected <T> T baseMakeResultSetToUniqueObject(RowMapper<T> mapper,ResultSet rs) throws NoFoundRowException, DaoException, SQLException{
		
		if(rs.next()){
			return mapper.currRow2Obj(rs);
		}
		if(mapper instanceof NullUniqueResultRowMapper<?>){
			return null;
		}
		throw new NoFoundRowException("没有查询到数据记录。");
	}
	
	protected <T> T baseQueryUniqueObject(RowMapper<T> mapper, String sql,Object... args) throws NoFoundRowException,DaoException, SQLException {
		
		ResultSet rs=baseQuery(baseSetArgs4PreparedStatement(baseCreatePreparedStatement(sql), args));	
			
		return this.baseMakeResultSetToUniqueObject(mapper, rs);	
			
		
	}
	
	

}